package org.reference.generic.operator;

import java.util.*;

import org.reference.generic.base.Item;
import org.reference.generic.base.Parameter;
import org.reference.generic.work.Job;
import org.reference.generic.work.Machine;
import org.reference.generic.work.MachineManager;

/**
 * 
 */

public abstract class Node extends Item {
    /**
     * 
     */
	protected Job job;
	protected Machine machine;
	protected MachineManager machineManager;
	
	private boolean rootNode=true;
	
    public Node(Parameter parameters) {
		maxDepth = parameters.getValueToInt(Parameter.TYPE_MAX_DEPTH);
		depth = parameters.getValueToInt(Parameter.TYPE_DEPTH);
		arity = parameters.getValueToInt(Parameter.TYPE_ARITY);

		if(this instanceof Terminal) return;

		branches = new ArrayList<Node>();
		for (int i=0; i < arity; ++i) {
			
			branches.add(NodeFactory.getRandomNode(maxDepth, getChildDepth(), arity));
		}
    }
    public int getChildDepth() {
		return depth + 1;
	}
    
	public int getDepth() {
		return depth;
	}
	
	
	
    /**
     * 
     */
    private Node root;

    /**
     * 
     */
    private int maxDepth;

    /**
     * 
     */
    private int depth;

    /**
     * 
     */
    private int arity;

    /**
     * 
     */
    private double resultValue;

    /**
     * 
     */
    protected boolean terminal = false;

    /**
     * 
     */
    protected ArrayList<Node> branches;

    public Node getChild(int index) { // 제거
    	return branches.get(index);
    }
    
    public int getChildNumber() { // 제거
    	return branches.indexOf(this);
    }
    
    protected void setResult(double value) {
    	resultValue = value;
    }
    /**
     * @return
     */
    public int getMaxDepth() {
        return maxDepth;
    }

    /**
     * @return
     */
    public int getArity() {
        return arity;
    }

    /**
     * @return
     */
    public double getResult() {
        return resultValue;
    }

    /**
     * @return
     */
    public boolean isTerminal() {
        return terminal;
    }

    /**
     * @param root
     */
    public void setRoot(Node root) {
    	this.root = root;
    }

    /**
     * @return
     */
    public Node getRoot() {
        return root;
    }
	public Job getJob() {

		return job;
	}
	
	
	public void setJob(Job job) {
		
		if(this instanceof Function){
		
		for(Node n : branches){
			n.setJob(job);
			}
		}
		
		this.job = job;
	}
	
	public Machine getMachine() {
		return machine;
	}
	
	public void setMachine(Machine machine) {
		
		if(this instanceof Function){
			
			for(Node n : branches){
				n.setMachine(machine);
			}
		}
		this.machine = machine;
	}
	
	public void setMachineManager(MachineManager machineManager) {
		
		if(this instanceof Function){
			
			for(Node n : branches){
				n.setMachineManager(machineManager);
			}
		}
		this.machineManager = machineManager;
	}
	
	public boolean isRootNode() {
		return rootNode;
	}
	
}